package com.plantplaces.service;

import java.util.ArrayList;
import java.util.List;

import android.content.Context;

import com.plantplaces.dao.IOfflinePlantDAO;
import com.plantplaces.dao.IPlantDAO;
import com.plantplaces.dao.OfflinePlantDAO;
import com.plantplaces.dao.OnlinePlantDAO;
import com.plantplaces.dto.Plant;
import com.plantplaces.dto.PlantSearch;

/**
 * Business logic for plants
 * @author jonesbr
 *
 */
public class PlantService implements IPlantService {

	IOfflinePlantDAO offlinePlantDAO;
	IPlantDAO onlinePlantDAO;

	public PlantService(Context context) {
		offlinePlantDAO = new OfflinePlantDAO(context);
		onlinePlantDAO = new OnlinePlantDAO();
	}

	@Override
	public List<Plant> fetchPlants(PlantSearch plantSearch) throws Exception {

		try {
			// retreive plants from PlantPlaces.com.
			ArrayList<Plant> allPlants = (ArrayList<Plant>) onlinePlantDAO.fetchPlants(plantSearch);

			// cache plants locally.
			// we must clone plants collection before we pass it to the array.
			cachePlants((ArrayList<Plant>) allPlants.clone());

			// return the plants.
			return allPlants;
		} catch (Exception e) {
			return offlinePlantDAO.fetchPlants(plantSearch);
		}

	}

	/**
	 * start a new thread to cache the plants that we have just received from the network.
	 * @param allPlants a collection of plants that we potentially want to cache.
	 */
	private void cachePlants(List<Plant> allPlants) {
		// instantiate an object of the inner class CachePlants.  This is a separate object, because it implements Runnable.
		CachePlants cp = new CachePlants(allPlants);
		// pass the object to a new thread.
		Thread cpThread = new Thread (cp);
		// invoke the start method on that thread which will start a new thread, and run the CachePlants object in that new thread.
		cpThread.start();
		
	}

	@Override
	public List<String> fetchGenus() throws Exception {
		return offlinePlantDAO.fetchGenus();
	}

	/**
	 * An inner class which implements Runnable.  The run method will run in a new thread when invoked.
	 * @author jonesbr
	 *
	 */
	class CachePlants implements Runnable {

		// The collection of plants that we wish to cache.
		List<Plant> allPlants;

		/**
		 * Parameterized constructor ensures that we have populated allPlatns if we have an object of this class.
		 * @param allPlants the collection of plants we want to cache.
		 */
		public CachePlants(List<Plant> allPlants) {
			this.allPlants = allPlants;
		}


		/**
		 * The run method will execute in a new thread when the start() method is executed on that thread.
		 */
		@Override
		public void run() {
			// TODO Auto-generated method stub
			// iterate over the collection of plants.
			for (Plant plant : allPlants) {

				try {
					if (offlinePlantDAO.fetchPlantByPlantPlacesId(plant.getGuid()) == null) {
						offlinePlantDAO.insert(plant);
					}
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}

			}		
			
		}
		
	}
	
}
